home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 5
/
Skunkware 5.iso
/
src
/
Games
/
xballs
/
xballs.c
< prev
Wrap
C/C++ Source or Header
|
1995-05-03
|
9KB
|
553 lines
/*
* Simple demo, animated (bouncing balls) background.
*
* Author: Bernard Hatt (bmh@terminus.ericsson.se)
*
* Camtec Electronics (Ericsson), Leicester, England, LE1 4SA
*
*/
#include <stdio.h>
#include <signal.h>
#include <ctype.h>
#include <sys/time.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/cursorfont.h>
Display *Disp;
int Scr;
Window Root;
GC GcF,GcB;
#define NONE 0 /* not in a window */
#define V 1 /* vertical */
#define H 2 /* horizontal */
#define B 3 /* ball */
#define MOUSEH 24
#define MOUSEW 24
#define DEFRAD 16 /* default diameter */
#define DEFNO 6
#define SPEED 128
#define SQLIMIT (SPEED*SPEED/(20*20)) /* square of lower speed limit */
int dispx,dispy;
typedef struct rectangle_struct
{
int x1,y1; /* x and y coords top left */
int x2,y2; /* x and y coords bottom right */
} RECTANGLE;
int nor;
RECTANGLE *rp=NULL;
typedef struct ball_struct
{
int x,y; /* x and y coords */
int dx,dy; /* x and y velocity */
} BALL;
int noballs=DEFNO;
int radius=DEFRAD;
BALL *bp;
int coeff=85;
int attop=100;
int backflag=0;
int invertflag=0;
int trailflag=0;
int mouseflag=1;
int sizeflag=0;
int momentumflag=0;
int interact=0;
int mx,my,mn,mdx,mdy;
int failed=0;
int currmax=0; /* current maximum number of windows */
char *getenv();
int lasttime;
long lastsec=0;
struct timezone tz={0,0};
struct timeval tv;
struct timeval tv2;
int
rnd(n)
int n;
{
return((rand()/153)%n);
}
void /* because Ultrix doesn't provide the nice SunOS usleep() */
myusleep(val)
int val;
{
tv2.tv_sec=0;
tv2.tv_usec=val;
select(0,NULL,NULL,NULL,&tv2);
}
void
dointr()
{
clearballs();
exit(1);
}
void
Xerr()
{
failed++;
}
void
Xfatal()
{
exit(1);
}
void
randomball(i)
int i;
{
int x,y;
int dum;
int attempts;
attempts=0;
do
{
x=rnd(dispx);
y=rnd(dispy);
if(rnd(100)<attop)
y=0;
attempts++;
if(attempts>2000)
{
clearballs();
exit(1);
}
}
while(inwin(x,y,0,0,&dum)!=NONE);
bp[i].x=x;
bp[i].y=y;
bp[i].dx=rnd(SPEED)+(SPEED/2);
bp[i].dy=rnd(SPEED)+(SPEED/2);
switch(rnd(4))
{
case 0:
break;
case 1:
bp[i].dx=(0-bp[i].dx);
break;
case 2:
bp[i].dy=(0-bp[i].dy);
break;
case 3:
bp[i].dx=(0-bp[i].dx);
bp[i].dy=(0-bp[i].dy);
break;
}
}
#ifdef SYSV
# include <sys/timeb.h>
#endif /*SYSV*/
int
gettime()
{
#ifdef SYSV
struct timeb tb;
ftime(&tb);
tv.tv_sec = tb.time;
tv.tv_usec = tb.millitm * 1000;
#else /*SYSV*/
gettimeofday(&tv,&tz);
#endif /*SYSV*/
if(lastsec==0)
lastsec=tv.tv_sec;
return((tv.tv_sec-lastsec)*100+(tv.tv_usec/10000));
}
int
inwin(x,y,dx,dy,n)
int x,y,dx,dy;
int *n;
{
int i,diffx,diffy;
int coln;
coln=(-1);
if((x<0)||(x>dispx))
return(V);
if((y<0)||(y>dispy))
return(H);
for(i=0;i<nor;i++)
{
if((x<rp[i].x1)||(y<rp[i].y1)||(y>rp[i].y2)||(x>rp[i].x2))
continue;
coln=i;
break;
}
if(coln==(-1))
{
if(!interact)
return(NONE);
for(i=0;i<noballs;i++)
{
if(i==(*n))
break;
diffx=(bp[i].x-x);
diffy=(bp[i].y-y);
if((diffx*diffx+diffy*diffy)<(radius*radius*4))
{
(*n)=i;
return(B);
}
}
return(NONE);
}
*n=coln;
x-=dx;
if((x<rp[i].x1)||(y<rp[i].y1)||(y>rp[i].y2)||(x>rp[i].x2))
return(V);
return(H);
}
clearballs()
{
int i;
XClearWindow(Disp,Root);
XFlush(Disp);
}
void
doballs()
{
int i,n;
int newtime,td;
int dx,dy,x,y,nx,ny;
int redo;
int diffx,diffy;
int dumint;
Window dumwin;
newtime=gettime();
td=newtime-lasttime;
if(td>20)
td=20;
if(mouseflag)
{
XQueryPointer(Disp,Root,&dumwin,&dumwin,&nx,&ny,&dumint,&dumint,&dumint);
mdx=nx-mx;
mx=nx;
mdy=ny-my;
my=ny;
rp[mn].x1=mx-(MOUSEW/2);
rp[mn].y1=my-(MOUSEH/2);
rp[mn].x2=mx+(MOUSEW/2);
rp[mn].y2=my+(MOUSEH/2);
}
for(i=0;i<noballs;i++)
{
if(backflag||trailflag)
XFillArc(Disp,Root,GcB,bp[i].x-(radius/2),bp[i].y-(radius/2),radius,radius,0,360*64);
else
XClearArea(Disp,Root,bp[i].x-(radius/2),bp[i].y-(radius/2),radius,radius,0);
redo=0;
if((bp[i].dx*bp[i].dx+bp[i].dy*bp[i].dy)<SQLIMIT)
redo=10;
do
{
dx=(td*bp[i].dx)/100;
dy=(td*bp[i].dy)/100;
if(redo>5)
{
redo=0;
randomball(i);
}
/* printf("coords are %d,%d [%d,%d]\n",bp[i].x,bp[i].y,bp[i].dx,bp[i].dy);*/
n=i;
switch(inwin(dx+bp[i].x,dy+bp[i].y,dx,dy,&n))
{
case NONE:
bp[i].x+=dx;
bp[i].y+=dy;
redo=0;
break;
case V:
if((n==mn)&momentumflag)
{
bp[i].dx=mdx;
bp[i].dy=mdy;
bp[i].x+=dx;
bp[i].y+=dy;
}
else
bp[i].dx=(coeff*bp[i].dx)/100;
redo++;
break;
case H:
if((n==mn)&momentumflag)
{
bp[i].dy=mdy;
bp[i].dx=mdx;
bp[i].x+=dx;
bp[i].y+=dy;
}
else
bp[i].dy=(coeff*bp[i].dy)/100;
if(coeff!=100)
{
/* printf("[%d] y=%d dy=%d\n",i,bp[i].y,dy);*/
if((bp[i].y>=(dispy-3))&&(dy<=5))
redo=10;
if((dx==0)&&(dy<=3))
redo=10;
}
redo++;
break;
case B:
diffx=bp[i].x-bp[n].x;
diffy=bp[i].y-bp[n].y;
break;
}
if(n==mn)
redo=0;
}
while(redo);
bp[i].dy+=td;
XFillArc(Disp,Root,GcF,bp[i].x-(radius/2),bp[i].y-(radius/2),radius,radius,0,360*64);
XFlush(Disp);
}
lasttime=newtime;
}
int
getwins()
{
int i;
Window dummy1,dummy2,*list;
XWindowAttributes WAttrib;
XEvent Event;
unsigned int listsize;
XQueryTree(Disp,Root,&dummy1,&dummy2,&list,&listsize);
if((listsize+2)>currmax)
{
if(rp!=NULL)
free(rp);
currmax=listsize+20;
/* printf("currmax=%d\n",currmax);*/
rp=(RECTANGLE*)malloc(sizeof(RECTANGLE)*currmax);
}
else
{
while(XCheckWindowEvent(Disp,Root,SubstructureNotifyMask,&Event))
{
while(XCheckWindowEvent(Disp,Root,SubstructureNotifyMask,&Event));
lasttime=gettime();
myusleep(50*1000);
}
}
if(rp==NULL)
{
fprintf(stderr,"Failed to malloc %d bytes\n",sizeof(RECTANGLE)*listsize*2);
exit(1);
}
nor=0;
for(i=0;i<listsize;i++)
{
failed=0;
XGetWindowAttributes(Disp,list[i],&WAttrib);
if((!failed)&&WAttrib.map_state==IsViewable)
{
rp[nor].x1=WAttrib.x;
rp[nor].y1=WAttrib.y;
rp[nor].x2=WAttrib.x+WAttrib.width;
rp[nor].y2=WAttrib.y+WAttrib.height;
/* printf("Window id 0x%x, x1=%d,y1=%d,x2=%d,y2=%d\n",list[nor],rp[nor].x1,rp[nor].y1,rp[nor].x2,rp[nor].y2);*/
nor++;
}
}
if(mouseflag)
{
mn=nor;
nor++;
}
XFree(list);
}
main(argc,argv)
int argc;
char *argv[];
{
unsigned long bg,fg;
char *dispname;
int i,j;
int x,y;
char *p;
XEvent Event;
srand(time(0));
dispname=getenv("DISPLAY");
for(i=1;i<argc;i++)
{
p=argv[i];
if(*p++=='-')
{
switch(*p++)
{
case 'd':
if(*p=='\0')
dispname=argv[++i];
else
dispname=p;
break;
case 'n':
if(*p=='\0')
noballs=atoi(argv[++i]);
else
noballs=atoi(p);
break;
case 'r':
if(*p=='\0')
radius=atoi(argv[++i]);
else
radius=atoi(p);
break;
case 'c':
if(*p=='\0')
coeff=atoi(argv[++i]);
else
coeff=atoi(p);
break;
case 't':
if(*p=='\0')
attop=atoi(argv[++i]);
else
attop=atoi(p);
break;
case 'b':
backflag=(!backflag);
break;
case 'i':
invertflag=(!invertflag);
break;
case 'm':
mouseflag=(!mouseflag);
break;
case 'M':
momentumflag=(!momentumflag);
break;
case 'I':
interact=(!interact);
break;
case 'l':
trailflag=(!trailflag);
break;
case 's':
sizeflag=(!sizeflag);
break;
default:
/* usage */
break;
}
}
}
if(coeff>100)
coeff=100;
if(coeff<0)
coeff=0;
coeff=(0-coeff);
bp=(BALL*)malloc(sizeof(BALL)*noballs);
if(bp==NULL)
{
fprintf(stderr,"Failed to malloc %d bytes\n",sizeof(BALL)*noballs);
exit(1);
}
Disp=XOpenDisplay(dispname);
Root=XDefaultRootWindow(Disp);
Scr=DefaultScreen(Disp);
clearballs();
if(noballs==0)
exit(0);
if(invertflag)
{
fg=BlackPixel(Disp,Scr);
bg=WhitePixel(Disp,Scr);
}
else
{
bg=BlackPixel(Disp,Scr);
fg=WhitePixel(Disp,Scr);
}
GcF=XCreateGC(Disp,Root,0,0);
GcB=XCreateGC(Disp,Root,0,0);
XSetForeground(Disp,GcF,fg);
XSetForeground(Disp,GcB,bg);
dispx=XDisplayWidth(Disp,Scr);
dispy=XDisplayHeight(Disp,Scr);
if(sizeflag)
fprintf(stderr,"Screen size is %dX by %dY\n",dispx,dispy);
if(backflag)
{
XSetWindowBackground(Disp,Root,bg);
XClearWindow(Disp,Root);
}
XSelectInput(Disp,Root,SubstructureNotifyMask);
/* printf("Width and Height are %d,%d\n",dispx,dispy);*/
getwins();
XFlush(Disp);
for(i=0;i<noballs;i++)
{
randomball(i);
}
lasttime=gettime();
signal(SIGINT,dointr);
signal(SIGHUP,dointr);
signal(SIGTERM,dointr);
XSetErrorHandler(Xerr);
XSetIOErrorHandler(Xfatal);
while(1)
{
if(XCheckWindowEvent(Disp,Root,SubstructureNotifyMask,&Event))
{
getwins();
}
doballs();
myusleep(50*1000);
}
}